﻿#region License
// /* **************************************************************
// * Copyright (C) intex Consulting GmbH - All Rights Reserved    *
// *--------------------------------------------------------------*
// * Unauthorized copying of this file, via any medium is         *
// * strictly prohibited                                          *
// *--------------------------------------------------------------*
// * Proprietary and confidential                                 *
// *--------------------------------------------------------------*
// * Dissasembling/modifications strictly prohibited!             *
// ***************************************************************/
#endregion
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using ComHlp.ContentClasses;
using ComHlp.ContentClasses.Bs;
using ComHlp.ContentClasses.FormDef;
using ComHlp.ContentClasses.VirtualControls;
using ComHlp.ContentClasses.VirtualControls.Buttons;
using ComHlp.ContentClasses.VirtualControls.LView;
using ComHlp.enums;
using ComHlp.enums.Fields;
using NLog;

namespace ComHlp.Classes.Parser
{
    internal class BsParser
    {
        private readonly Logger _log = LogManager.GetCurrentClassLogger();

        /// <summary> default constructor </summary>
        /// <exception cref="ArgumentNullException"><paramref name="sbRecvStr"/> is <see langword="null" />.</exception>
        internal BsHeader ParseBsHead(StringBuilder sbRecvStr)
        {
            if (sbRecvStr == null) throw new ArgumentNullException(nameof(sbRecvStr));

            // check map
            BsHeader bsHeader = new BsHeader {MapName = sbRecvStr.ToString(0, 8).TrimEnd()};
            sbRecvStr.Remove(0, 8);

            bsHeader.RestB = sbRecvStr.ToString(0, 48);
            bsHeader.UserId = sbRecvStr.ToString(48, 8);
            UpdateFunctionKeys(sbRecvStr.ToString(56, 20));
            //todo bsHeader.Format = sbRecvStr.ToString(76, 316);
            bsHeader.StartProg = sbRecvStr.ToString(392, 4);
            // filler of 4 chars
            sbRecvStr.Remove(0, 400);

            bsHeader.Graphic = sbRecvStr[0] == 'J';
            bsHeader.DatKz = sbRecvStr[1];
            bsHeader.ListViewScroll = sbRecvStr[2];
            bsHeader.MouseLr = sbRecvStr[3];
            bsHeader.MenuInfo = sbRecvStr[4];
            bsHeader.ListView = sbRecvStr[5] == 'J';
            switch (sbRecvStr[6])
            {
                case '1':
                    bsHeader.DataLink = DataLinkState.LinkFree;
                    break;
                case '2':
                    bsHeader.DataLink = DataLinkState.LinkEstablished;
                    break;
                default:
                    bsHeader.DataLink = DataLinkState.Hidden;
                    break;
            }
            bsHeader.ServerTrace = sbRecvStr[7];
            bsHeader.OemConv = sbRecvStr[8];
            bsHeader.DlZuord = sbRecvStr[9];
            bsHeader.MouseMove = sbRecvStr[10];
            bsHeader.Reserve2 = sbRecvStr.ToString(11, 7);
            bsHeader.MouseX = ParseHelper.String2Int(sbRecvStr.ToString(18, 4));
            bsHeader.MouseY = ParseHelper.String2Int(sbRecvStr.ToString(22, 4));
            bsHeader.CursorPos = ParseHelper.String2Int(sbRecvStr.ToString(26, 4));
            sbRecvStr.Remove(0, 30);

            return bsHeader;
        }

        /// <summary>
        /// parse the bs sentence and add the field content to the map definition
        /// </summary>
        /// <param name="bsCursorPosition"></param>
        /// <param name="sbRecvStr"></param>
        /// <param name="formDefMap"></param>
        /// <exception cref="ArgumentNullException"></exception>
        /// <exception>Condition.</exception>
        internal ItxStatus FillFormDefFields(int bsCursorPosition, StringBuilder sbRecvStr, ref FormDefMap formDefMap)
        {
            if (sbRecvStr == null) throw new ArgumentNullException(nameof(sbRecvStr));
            
            // get all attributes in one string to parse them in parallel with the field content
            int attrLength = 10 * formDefMap.Header.MapFieldCount;
            StringBuilder sbAttributes = new StringBuilder(sbRecvStr.ToString(0, attrLength));
            sbRecvStr.Remove(0, attrLength);

            // helpvars for cursorposition
            int posCalc = 0;    
            bool posFound = false;
            StringBuilder statusMsg = new StringBuilder();

            // add field content and attributes to each field
            foreach (ItxField itxField in formDefMap.Fields)
            {
                // attributes
                string bsAttribute = sbAttributes.ToString(0, 10);
                itxField.RecvBsAttribute = bsAttribute;
                itxField.BsColorNo = GetBsAttributeColorNo(itxField.RecvBsAttribute);
                itxField.BsAttribute = ParseBsFieldAttribute(bsAttribute);
                sbAttributes.Remove(0, 10);

                // cursor position
                if (!posFound)
                {
                    posCalc = posCalc + 2;
                    if (posCalc + itxField.Length >= bsCursorPosition && posCalc <= bsCursorPosition)
                    {
                        itxField.BsCursorField = true;
                        posFound = true;
                    }
                    else
                        itxField.BsCursorField = false;

                    posCalc = posCalc + itxField.Length;
                }
                else
                    itxField.BsCursorField = false;

                // have we received the same amount of bytes?
                if (ComStatics.UseUtf8)
                    itxField.BsContent = ParseHelper.ExtractUtf8(itxField.Length, sbRecvStr, true);
                else
                {
                    // content
                    itxField.BsContent = sbRecvStr.ToString(0, itxField.Length);
                    sbRecvStr.Remove(0, itxField.Length);
                }

                // analyze for status
                // check status message
                if (itxField.FormDefName.Length != 8)
                    continue;
                

                switch (itxField.FormDefName)
                {
                    case ItxControlConstants.StatusMessage1: // sepecial field (message line)
                         statusMsg.Append(itxField.BsContent);
                        break;
                    case ItxControlConstants.StatusMessage2: // sepecial field (message line)
                        if (itxField.BsContent.Length > 0)
                            statusMsg.Append(itxField.BsContent);
                        break;
                    case ItxControlConstants.StatusMessage3: // sepecial field (message line)
                        if (itxField.BsContent.Length > 0)
                            statusMsg.Append(itxField.BsContent);
                        break;
                }
            }

            return new ItxStatus(statusMsg.ToString());
        }

        /// <summary> Extract the map name from bssentence </summary>
        /// <param name="bs"></param>
        /// <returns></returns>
        internal string GetMapNameFromBs(StringBuilder bs)
        {
            return bs.Length > 8 ? bs.ToString(0, 8).TrimEnd() : "";
        }


        /// <summary> set attributes from received string </summary>
        /// <param name="sbRecvStr"></param>
        /// <param name="bsMap"></param>
        /// <returns>null if no tabpages </returns>
        internal void ParseBsMessageArea(StringBuilder sbRecvStr, BsMap bsMap)
        {
            // temp list for saving button attributes
            List<bool> buttonsStateAttribute = new List<bool>();
            while (sbRecvStr.Length > 0)
            {
                // get length
                int length;
                if (!int.TryParse(sbRecvStr.ToString(0, 4), out length) || length == 0)
                    break;

                // remove length
                sbRecvStr.Remove(0, 4);
                length = length - 4;
                
                // get what we got
                string evalValue = sbRecvStr.ToString(0, 4);

                // remove identifier (type specification)
                sbRecvStr.Remove(0, 4);
                length = length - 4;

                // skip if length is 0
                if (length == 0)
                    continue;

                switch (evalValue)
                {
                    // bk - 'buttonkontrolle'...
                    case "BK1 ":
                        // we got more than 1 button
                        if (length > 10)
                        {   // calc times
                            int offSet = 0;
                            int i = (int)Math.Ceiling((decimal)length / 10);
                            for (; i > 0; i--)
                            {
                                buttonsStateAttribute.Add(sbRecvStr.ToString(offSet, 1) == "J");
                                offSet = offSet + 10;
                            }
                        }
                        // we got only 1 button - 'space savings...............................'
                        else if (length > 0)
                            buttonsStateAttribute.Add(sbRecvStr.ToString(0, 1) == "J");

                        sbRecvStr.Remove(0, length);
                        continue;
                    // system buttons
                    case "SB2 ":
                    case "SB3 ":
                        ParseBsMessageAreaMsgButtonOrMacro(sbRecvStr, length, buttonsStateAttribute, bsMap);
                        continue;
                        // user config aus DS28
                    case "SC1 ":
                        // get colors
                        ParseBsGraphicArea(sbRecvStr);
                        // remove parsed content
                        sbRecvStr.Remove(0, length);
                        continue;
                    case "SR1 ":
                        // get tabs
                        bsMap.TabPages = ParseBsMessageAreaTabPages(sbRecvStr, length);
                        continue;
                    case "DI1 ": //TODO
#if DEBUG
                        _log.Debug($"Unknown bs message area type '{evalValue}' received");
#endif
                        // remove parsed content
                        sbRecvStr.Remove(0, length);
                        continue;
                    case "LVS1":
                        /* linker listview ganz links:	LVS1 10100000000044000
                         * linker listview mitte iwo :	LVS1 10500000000044000
                         * linker listview ganz recht:	LVS1 10900000000042000
                         * linker listview ganz links
                         * recht listview eins rechts: LVS1 50100000000044000
                         * recht listview ganz rechts: LVS1 90100000000024000
                         * *----------------------------------------------------------------*
                         * *  GESAMTLAENGE 26 (4 LAENGE, 4 "LVS1", 12 SCROLL, 6 PP)         *
                         * *----------------------------------------------------------------*
                         *         05       DBZ-LISTVIEW-SCROLL.
                         *         10     FILLER             OCCURS 6.
                         *          15  DBZ-LISTVIEW-LINKSRECHTS    PIC X(001).
                         *              VORGABE FUER SCROLL-BALKEN DES LISTVIEWS
                         *              0=INAKTIV, GANZE BEITE / 1=LINKS / 5=MITTE / 9=RECHTS
                         *              
                         *         15   DBZ-LISTVIEW-OBENUNTEN      PIC X(001).
                         *              VORGABE FUER SCROLL-BALKEN DES LISTVIEWS
                         *              0=INAKTIV, GANZE HOEHE / 1=OBEN / 5=MITTE / 9=UNTEN
                         *              
                         *         15   DBZ-LISTVIEW-PP    PIC 9(001).  PLUPLU/LILI/RERE KENNZ
                         *              1=PLUPLU / 2=LILI / 4=RERE
                         *              DIE WERTE SIND IN SUMME IM FELD
                         */
                        bsMap.ListViewPaging = new ListViewPagingInformation();
                        bsMap.ListViewPaging.ListViewHorizontal[0] = ParseListViewPagingInformation(sbRecvStr[0]);
                        bsMap.ListViewPaging.ListViewVertical[0] = ParseListViewPagingInformation(sbRecvStr[1]);

                        bsMap.ListViewPaging.ListViewHorizontal[1] = ParseListViewPagingInformation(sbRecvStr[2]);
                        bsMap.ListViewPaging.ListViewVertical[1] = ParseListViewPagingInformation(sbRecvStr[3]);

                        bsMap.ListViewPaging.ListViewHorizontal[2] = ParseListViewPagingInformation(sbRecvStr[4]);
                        bsMap.ListViewPaging.ListViewVertical[2] = ParseListViewPagingInformation(sbRecvStr[5]);

                        bsMap.ListViewPaging.ListViewHorizontal[3] = ParseListViewPagingInformation(sbRecvStr[6]);
                        bsMap.ListViewPaging.ListViewVertical[3] = ParseListViewPagingInformation(sbRecvStr[7]);

                        bsMap.ListViewPaging.ListViewHorizontal[4] = ParseListViewPagingInformation(sbRecvStr[8]);
                        bsMap.ListViewPaging.ListViewVertical[4] = ParseListViewPagingInformation(sbRecvStr[9]);

                        bsMap.ListViewPaging.ListViewHorizontal[5] = ParseListViewPagingInformation(sbRecvStr[10]);
                        bsMap.ListViewPaging.ListViewVertical[5] = ParseListViewPagingInformation(sbRecvStr[11]);

                        bsMap.ListViewPaging.ListViewNavigation[0] = ParseListViewNavigation(sbRecvStr[12]);
                        bsMap.ListViewPaging.ListViewNavigation[1] = ParseListViewNavigation(sbRecvStr[13]);
                        bsMap.ListViewPaging.ListViewNavigation[2] = ParseListViewNavigation(sbRecvStr[14]);
                        bsMap.ListViewPaging.ListViewNavigation[3] = ParseListViewNavigation(sbRecvStr[15]);
                        bsMap.ListViewPaging.ListViewNavigation[4] = ParseListViewNavigation(sbRecvStr[16]);
                        bsMap.ListViewPaging.ListViewNavigation[5] = ParseListViewNavigation(sbRecvStr[17]);

                        // remove parsed content
                        sbRecvStr.Remove(0, length);
                        break;
                    default:
                        // remove parsed content
#if DEBUG
                        _log.Debug($"Unknown bs message area type '{evalValue}' received");
#endif
                        sbRecvStr.Remove(0, length);
                        continue;
                }
            }
        }

        private List<ItxTabPage> ParseBsMessageAreaTabPages(StringBuilder sbRecvStr, int length)
        {
            /* sample message:
             * [431000     FC      AB02    Auftraege suchen
                441000     FC      AB04    Auftragskopfdaten
                381000     FC      AB50    Garnauftrag
                391002     FKT     SR      Stamminfo RW
                391002     FKT     SF      Stamminfo FW
                571002     FKT     SM      Stamminfo Komposition
                361002     FC      AB04    Kopfdaten
                371000     FC      F3      neue Suche
                451000     FC      VK03    Auftragsuebersicht
                391000     CUA;FC  I;VK04  Auftragskopf
                431000     CUA;FC  I;VK35  Auftragsposition
                321000     CUA;FC  H       Texte
             * Lä		9(02)	Länge des Reitereintrags
             * Filler		X(09)
             * Feldname	X(08)	Feldname
             * Wert		X(08)	Wert für das Feld
             * Text	X(var) 	Text des Reiters (in der Lä – 27)
            */
            List<ItxTabPage> tabPages = new List<ItxTabPage>();
            while (length > 0)
            {
                // get current tab entry length and subtract it from length
                int tabLength = ParseHelper.String2Int(sbRecvStr.ToString(0, 2));
                length -= tabLength;

                // save class
                ItxTabPage tabPage = new ItxTabPage();

                string field = sbRecvStr.ToString(11, 8).Trim();
                string fieldValue = sbRecvStr.ToString(19, 8);
                if (field.Contains(';'))
                {
                    string[] splitField = field.Split(';');
                    tabPage.Field = splitField[0];
                    tabPage.Field2 = splitField[1];

                    string[] splitValue = fieldValue.Split(';');
                    tabPage.FieldValue = splitValue[0];
                    if (splitValue.Length > 1)
                        tabPage.FieldValue2 = splitValue[1];
                }
                else
                {
                    tabPage.Field = field;
                    tabPage.FieldValue = fieldValue;
                }

                // cut
                sbRecvStr.Remove(0, 27);
                tabLength -= 27;

                if (tabLength <= 0)
                    break;

                // get title
                string title;
                if (ComStatics.UseUtf8)
                    title = ParseHelper.ExtractUtf8(tabLength, sbRecvStr, true).Trim();
                else
                {
                    title = sbRecvStr.ToString(0, tabLength).Trim();
                    sbRecvStr.Remove(0, tabLength);
                }
                // set spaces
                tabPage.Title = title.Replace('#', ' ');
                tabPages.Add(tabPage);
            }
            return tabPages;
        }

        private void ParseBsMessageAreaMsgButtonOrMacro(StringBuilder sbRecvStr, int length, IList<bool> enabledButtons, BsMap bsMap)
        {
            int lastButId = -1;
            ButtonParseHelper buttonParseHelper = new ButtonParseHelper();

            bool lastParsedWasButton = false;

            while (length > 60)
            {
                int butLength = ParseHelper.String2Int(sbRecvStr.ToString(0, 2));
                ItxButton button = new ItxButton(ItxHorizontalAlignment.Center);

                // type and rest of definition
                EItxBsMsgAreaButtonOrMacroMessageType recvType;
                switch (sbRecvStr[2])
                {
                    case 'B':
                    case 'F':
                        recvType = EItxBsMsgAreaButtonOrMacroMessageType.Button;
                        break;
                    case 'M':
                        recvType = EItxBsMsgAreaButtonOrMacroMessageType.Macro;
                        break;
                    case ' ':
                        recvType = EItxBsMsgAreaButtonOrMacroMessageType.SubDefinition;
                        break;
                    default:
#if DEBUG
                        _log.Debug($"Unknown bs msg area button received: {sbRecvStr}");
#endif
                        // remove length
                        sbRecvStr.Remove(0, butLength);
                        length -= butLength;
                        continue;
                }
                button.Pos = sbRecvStr[3];
                button.Top = ParseHelper.String2Int(sbRecvStr.ToString(3, 4));
                button.Bottom = ParseHelper.String2Int(sbRecvStr.ToString(7, 4));
                button.Left = ParseHelper.String2Int(sbRecvStr.ToString(11, 4));
                button.Right = ParseHelper.String2Int(sbRecvStr.ToString(15, 4));
                button.Form = buttonParseHelper.ParseButtonForm(sbRecvStr.ToString(19, 2));
                button.Icon = sbRecvStr.ToString(21, 2);
                button.ButtonNo = ParseHelper.String2Int(sbRecvStr.ToString(23, 2));
                string field = sbRecvStr.ToString(25, 8).Trim();
                button.ShortCutKey = buttonParseHelper.ParseFunctionKey(sbRecvStr.ToString(33, 2));
                button.ActionType = buttonParseHelper.ParseAction(sbRecvStr.ToString(35, 3));
                button.BgColor = new ItxColor(255, Convert.ToByte(sbRecvStr.ToString(38, 3)), Convert.ToByte(sbRecvStr.ToString(41, 3)), Convert.ToByte(sbRecvStr.ToString(44, 3)));
                button.FgColor = new ItxColor(255, Convert.ToByte(sbRecvStr.ToString(47, 3)), Convert.ToByte(sbRecvStr.ToString(50, 3)), Convert.ToByte(sbRecvStr.ToString(53, 3)));
                button.FontNo = ParseHelper.String2Int(sbRecvStr.ToString(56, 2));
                button.FontFact = sbRecvStr.ToString(58, 2);

                if (butLength < 60)
                    break;

                // cut
                sbRecvStr.Remove(0, 60);
                length -= 60;
                butLength -= 60;

                string textAndValue;
                if (ComStatics.UseUtf8)
                {
                    textAndValue = ParseHelper.ExtractUtf8(butLength, sbRecvStr, true);
                    length -= butLength;
                }
                else
                {
                    textAndValue = sbRecvStr.ToString(0, butLength);
                    // remove length
                    sbRecvStr.Remove(0, butLength);
                    length -= butLength;
                }

                // parse 
                //string[] splitTmp = sbRecvStr.ToString(0, butLength).Split(new[] {";;"}, StringSplitOptions.None);
                string[] splitTmp = textAndValue.Split(new[] {";;"}, StringSplitOptions.None);
                string value = null;
                if (splitTmp.Length == 2)
                {
                    button.Text = splitTmp[0];
                    value = splitTmp[1];
                }

                // check if we got an action or a complete button
                if (button.Text.Length == 0 && lastButId > -1)
                    button.ButtonNo = lastButId; // additional action, we set the id to the previous one
                else
                    lastButId = button.ButtonNo; // no additional action, we set the last button id

                // check if we shall display or not
                if (button.ButtonNo > 0)
                {
                    if (enabledButtons.Count >= button.ButtonNo)
                    {
                        bool enabled = enabledButtons[button.ButtonNo - 1]; //-1 offset fix between cobol and c#
                        button.Enabled = enabled;
                    }
                    else //received no attributes, so disabled
                        button.Enabled = false;
                }

                // determine if it is a new definition or a subdefinition
                //  dpeneding on that we need to move it to different list
                switch (recvType)
                {
                    case EItxBsMsgAreaButtonOrMacroMessageType.SubDefinition:
                        if (lastParsedWasButton && bsMap.Buttons.Count == 0)
                            continue;
                        if(!lastParsedWasButton && bsMap.ServerMacros.Count == 0)
                            continue;

                        
                        ItxButton lastbutton = lastParsedWasButton ? bsMap.Buttons.Last() : bsMap.ServerMacros.Last();
                        lastbutton.Actions.Add(new ItxButtonAction(field, value, button.ActionType));
                        break;

                    case EItxBsMsgAreaButtonOrMacroMessageType.Macro:
                        ItxButtonAction macroAction = new ItxButtonAction(field, value, button.ActionType);
                        button.AssignedField = field;
                        button.Actions.Add(macroAction);
                        bsMap.ServerMacros.Add(button);

                        lastParsedWasButton = false;
                        break;

                    case EItxBsMsgAreaButtonOrMacroMessageType.Button:
                        ItxButtonAction buttonAction = new ItxButtonAction(field, value, button.ActionType);
                        button.AssignedField = field;
                        button.Actions.Add(buttonAction);
                        bsMap.Buttons.Add(button);

                        lastParsedWasButton = true;
                        break;
                }
            }
        }

        private void ParseBsGraphicArea(StringBuilder sb)
        {
            //
            // start parsing
            // copy to local string
            string localStr = sb.ToString();
            while (localStr.Length > 0)
            {
                // get new string data length
                int length;
                if (!int.TryParse(localStr.Substring(0, 2), out length))
                    return;

                if (length == 0)
                    return;

                // get the part to parse in length -2 for length definition
                string part2Parse = localStr.Substring(2, length - 2);

                // parse
                ParseBsGraphicAreaMsgAreaValue(part2Parse);

                // cut parsed string
                localStr = localStr.Remove(0, length);
            }
        }

        /// <summary> check if the field needs to get disabled or has errenous input </summary>
        /// <param name="bsAttributes"></param>
        /// <returns></returns>
        private ItxFieldState ParseBsFieldAttribute(string bsAttributes)
        {
            ItxFieldState retVal = ItxFieldState.Normal;
            switch (bsAttributes)
            {
                case "0000000000": // ausgabe hell
                    return ItxFieldState.Normal;
                case "0000000288":
                    return ItxFieldState.Disabled;
                case "0000004388": // ausgabe hell
                case "0000004384": // ausgabe hell
                case "0000004360": // ausgabe normal
                    return ItxFieldState.Disabled;
                case "0000000512":
                case "0000001024":
                case "0000001536":
                    return ItxFieldState.DisabledWarning;
                case "0000002560":
                case "0000016416": //todo
                    return ItxFieldState.Normal;
                case "0000020484": // eingabe dunkel
                    return ItxFieldState.Normal;
                case "0000020424":
                case "0000020514":
                    return ItxFieldState.Errenous;
                case "0000020488": //todo
                case "0000020512": //todo
                case "0000003072": //todo
                case "0000002048": //todo
                    return ItxFieldState.Normal;
            }

            // check disable state
            switch (bsAttributes.Substring(bsAttributes.Length - 4))
            {
                case "4388": // ausgabe hell
                case "4384": // ausgabe hell
                case "4360": // ausgabe normal
                    retVal = ItxFieldState.Disabled;
                    break;
                case "0512":
                case "1024":
                case "1536":
                    retVal = ItxFieldState.DisabledWarning;
                    break;
            }

            //ausgabe dunkel
            if (bsAttributes.Substring(bsAttributes.Length - 3) == "288")
                retVal = ItxFieldState.Disabled;

            // check errenous input
            switch (bsAttributes.Substring(bsAttributes.Length - 5))
            {
                case "16416": // eingabe dunkel
                    break;
                case "20424":
                case "20514":
                    retVal = ItxFieldState.Errenous;
                    break;
                case "20484": // eingabe dunkel
                    break;
                case "20488": // eingabe normal
                    break;
                case "20512": // eingabe hell
                    break;
            }

            return retVal;
        }

        private void ParseBsGraphicAreaMsgAreaValue(string msgAreaPart)
        {
            // seperate value and identifier 
            string identifier = msgAreaPart.Substring(0, 8).TrimEnd();
            string value = msgAreaPart.Substring(8);

            switch (identifier)
            {
                case "BACKH": // background color
                    BsGraphicsArea.BackgroundBgColor = ParseHelper.String2Color(value);
                    break;
                //case "BACKV": // foreground color
                //    BsGraphicsArea.BackgroundFgColor = ParseHelper.String2Color(value);
                //    break;
                //case "EHH": // input bright backcolor
                //    BsGraphicsArea.InputBrightBgColor = ParseHelper.String2Color(value);
                //    break;
                //case "EHV": // input bright frontcolor
                //    BsGraphicsArea.InputBrightFgColor = ParseHelper.String2Color(value);
                //    break;
                case "EHIH": // input bright selected backcolor
                    BsGraphicsArea.InputBrightSelectedBgColor = ParseHelper.String2Color(value);
                    break;
                //case "EHIV": // input bright selected forecolor
                //    BsGraphicsArea.InputBrightSelectedFgColor = ParseHelper.String2Color(value);
                //    break;
                case "EHIIH": // insert mode background
                    BsGraphicsArea.InsertModeBgColor = ParseHelper.String2Color(value);
                    break;
                //case "EHIIV": // insert mode foreground
                //    BsGraphicsArea.InsertModeFgColor = ParseHelper.String2Color(value);
                //    break;
                //case "EPH": // constraint field
                //    BsGraphicsArea.ConstraintFieldBgColor = ParseHelper.String2Color(value);
                //    break;
                //case "ERRH": // errenous input backcolor
                //    BsGraphicsArea.ErrorBgColor = ParseHelper.String2Color(value);
                //    break;
                //case "ERRV": // errenous input forecolor
                //    BsGraphicsArea.ErrorFgColor = ParseHelper.String2Color(value);
                //    break;
                //case "MSGH": // message line backcolor
                //    BsGraphicsArea.MsgLineBgColor = ParseHelper.String2Color(value);
                //    break;
                //case "MSGV": // message line forecolor
                //    BsGraphicsArea.MsgLineFgColor = ParseHelper.String2Color(value);
                //    break;
                //case "HELPH": // helpfield
                //    BsGraphicsArea.HelpFieldColor = ParseHelper.String2Color(value);
                //    break;
                //case "BUTTH": // button backcolor
                //    BsGraphicsArea.ButtonBgColor = ParseHelper.String2Color(value);
                //    break;
                //case "BUTTM": // hovered button
                //    BsGraphicsArea.ButtonHoverColor = ParseHelper.String2Color(value);
                //    break;
                //case "AHV": // output bright
                //    BsGraphicsArea.OutputBrightFgColor = ParseHelper.String2Color(value);
                //    break;
                //case "A1V": // color 1
                //    BsGraphicsArea.OutputC1FgColor = ParseHelper.String2Color(value);
                //    break;
                //case "A2V": // color 2
                //    BsGraphicsArea.OutputC2FgColor = ParseHelper.String2Color(value);
                //    break;
                //case "A3V": // color 3
                //    BsGraphicsArea.OutputC3FgColor = ParseHelper.String2Color(value);
                //    break;
                //case "A4V": // color 4
                //    BsGraphicsArea.OutputC4FgColor = ParseHelper.String2Color(value);
                //    break;
                //case "A5V": // color 5
                //    BsGraphicsArea.OutputC5FgColor = ParseHelper.String2Color(value);
                //    break;
                //case "A6V": // color 6
                //    BsGraphicsArea.OutputC6FgColor = ParseHelper.String2Color(value);
                //    break;
                //case "GIFV": // interface forecolor
                //    BsGraphicsArea.InterfaceFgColor = ParseHelper.String2Color(value);
                //    break;
                //case "GIFH": // interface backcolor
                //    BsGraphicsArea.InterfaceBgColor = ParseHelper.String2Color(value);
                //    break;
                //case "SCB": // scrollbar
                //    BsGraphicsArea.ScrollBarColor = ParseHelper.String2Color(value);
                //    break;
                case "K1": // color K1
                    BsGraphicsArea.K1Color = ParseHelper.String2Color(value);
                    break;
                case "K2": // color K2
                    BsGraphicsArea.K2Color = ParseHelper.String2Color(value);
                    break;
                case "S1": // color S1
                    BsGraphicsArea.S1Color = ParseHelper.String2Color(value);
                    break;
                case "S2": // color S2
                    BsGraphicsArea.S2Color = ParseHelper.String2Color(value);
                    break;
                //case "SYS1": // color S2
                //    BsGraphicsArea.Sys1Color = ParseHelper.String2Color(value);
                //    break;
                //case "GTC": // tabcontrol
                //    BsGraphicsArea.TabColor = ParseHelper.String2Color(value);
                //    break;
                //case "GTCS": // tab selected
                //    BsGraphicsArea.SelectedTabColor = ParseHelper.String2Color(value);
                //    break;
                //case "FONT1":
                //    BsGraphicsArea.Font1Window = ParseHelper.String2Font(value);
                //    break;
                //case "FONT2":
                //    BsGraphicsArea.Font2Input = ParseHelper.String2Font(value);
                //    break;
                case "FONTC":
                    //BsGraphicsArea.FontCFixed = ParseHelper.String2Font(value);
                    BsGraphicsArea.FontCFixed.UpdateFontWithFactor(150);
                    break;
                //case "FONT3":
                //    BsGraphicsArea.Font3ListView = ParseHelper.String2Font(value);
                //    break;
                case "FONTFAK1": //"0100"
                    BsGraphicsArea.Font1Factor = ParseHelper.String2Int(value);
                    BsGraphicsArea.Font1Window.UpdateFontWithFactor(BsGraphicsArea.Font1Factor);
                    break;
                case "FONTFAK2": //0090
                    BsGraphicsArea.Font2Factor = ParseHelper.String2Int(value);
                    BsGraphicsArea.Font2Input.UpdateFontWithFactor(BsGraphicsArea.Font2Factor);
                    break;
                case "FONTFAK3": //"009711"
                    BsGraphicsArea.Font3Factor = ParseHelper.String2Int(value);
                    BsGraphicsArea.Font3ListView.UpdateFontWithFactor(BsGraphicsArea.Font3Factor);
                    break;
                case "RAH1":
                    // obsolet
                    break;
                case "EDGE":
                    // obsolet
                    break;
                case "EDITEDGE": //114
                    // TODO
                    break;
                case "FKEY1": //ignored up to now -"1001020304050607080910111213141516171819202122232425"
                    // TODO
                    break;
                case "FKEY2": //ignored up to now -"26272829303132333435363738394041424344454647484950"
                    // TODO
                    break;
                case "VERLK1": //"A7"
                    // TODO
                    break;
                case "VERLK2": //"C9"
                    // TODO
                    break;
                case "VERLS1": //"G5"
                    // TODO
                    break;
                case "VERLS2": //"12"
                    // TODO
                    break;
                case "VERLMSG1": //"K9"
                    // TODO
                    break;
                case "HELPTYP": //"D"
                    // TODO
                    break;
                case "EDITY": //"0009"
                    BsGraphicsArea.LineSpacing = ParseHelper.String2Int(value);
                    break;
                case "VERLBUTT": //"A9"
                    // TODO
                    break;
                case "VERLBU23": //"A9"
                    // TODO
                    break;
                case "VERLTC": //ignored up to now -"A9"
                    // TODO
                    break;
                case "TC": //ignored up to now -"132186253"
                    // TODO
                    break;
                case "TCS": //ignored up to now -"255217136"
                    // obsolet
                    break;
                case "T100":
                    ParseBsGraphicsAreaMsgAreaStrTrans(value);
                    break;
                case "CMDE":
                    BsGraphicsArea.ExcelCommand = value;
                    break;
                case "CMDM":
                    BsGraphicsArea.MailCommand = value;
                    break;
                case "CODEPG":
                    BsGraphicsArea.Codepage = value;
                    break;
                case "TIMESTAMP":
                    BsGraphicsArea.ServerTime = value;
                    break;
            }
        }

        /// <summary>  parse the possible navigation of listview
        /// 15   DBZ-LISTVIEW-PP    PIC 9(001).  PLUPLU/LILI/RERE KENNZ
        /// 1=PLUPLU (top page) / 2=LILI (first page) / 4=RERE (last page)
        /// DIE WERTE SIND IN SUMME IM FELD </summary>
        /// <param name="navigationIdentifier"></param>
        /// <returns></returns>
        private static ListViewFastNavigation ParseListViewNavigation(char navigationIdentifier)
        {
            switch (navigationIdentifier)
            {
                default:
                    return null;
                case '1':
                    return new ListViewFastNavigation(true, false, false);
                case '2':
                    return new ListViewFastNavigation(false, true, false);
                case '3':
                    return new ListViewFastNavigation(true, true, false);
                case '4':
                    return new ListViewFastNavigation(false, false, true);
                case '5':
                    return new ListViewFastNavigation(true, false, true);
                case '6':
                    return new ListViewFastNavigation(false, true, true);
                case '7':
                    return new ListViewFastNavigation(true, true, true);
            }
        }

        private static EListViewPagingPosition ParseListViewPagingInformation(char scrollIdentifier)
        {
            switch (scrollIdentifier)
            {
                case '1':
                    return EListViewPagingPosition.First;
                case '2':
                case '3':
                case '4':
                case '5':
                case '6':
                case '7':
                case '8':
                    return EListViewPagingPosition.Middle;
                case '9':
                    return EListViewPagingPosition.Last;
                default:
                    return EListViewPagingPosition.NoScroll;
            }
        }

        /// <summary> Prase bs message area translations </summary>
        /// <param name="value"></param>
        private void ParseBsGraphicsAreaMsgAreaStrTrans(string value)
        {
            StringBuilder sb = new StringBuilder(value);
            // check if we received the translation by searching for t100

            // parse following
            while (sb.Length > 0)
            {
                string evalVal = sb.ToString(0, 2).Trim();

                // default cut length is 2, we check if the string is ending afterwards...
                int cutLength = 2;
                if (sb.Length < 4)
                    cutLength = 1;

                switch (evalVal)
                {
                    case "J":
                        BsGraphicsArea.TranslateTable100Yes = sb.ToString(2, cutLength).Trim();
                        break;
                    case "N":
                        BsGraphicsArea.TranslateTable100No = sb.ToString(2, cutLength).Trim();
                        break;
                    case "U":
                        BsGraphicsArea.TranslateTable100Unclear = sb.ToString(2, cutLength).Trim();
                        break;
                    case "A":
                        BsGraphicsArea.TranslateTable100A = sb.ToString(2, cutLength).Trim();
                        break;
                    case "I":
                        BsGraphicsArea.TranslateTable100I = sb.ToString(2, cutLength).Trim();
                        break;
                    case "K":
                        BsGraphicsArea.TranslateTable100K = sb.ToString(2, cutLength).Trim();
                        break;
                    case "P":
                        BsGraphicsArea.TranslateTable100P = sb.ToString(2, cutLength).Trim();
                        break;
                    case "S":
                        BsGraphicsArea.TranslateTable100S = sb.ToString(2, cutLength).Trim();
                        break;
                    case "R":
                        BsGraphicsArea.TranslateTable100R = sb.ToString(2, cutLength).Trim();
                        break;
                    case "W":
                        BsGraphicsArea.TranslateTable100W = sb.ToString(2, cutLength).Trim();
                        break;
                    case "V":
                        BsGraphicsArea.TranslateTable100V = sb.ToString(2, cutLength).Trim();
                        break;
                    case "T":
                        BsGraphicsArea.TranslateTable100T = sb.ToString(2, cutLength).Trim();
                        break;
                    case "G":
                        BsGraphicsArea.TranslateTable100G = sb.ToString(2, cutLength).Trim();
                        break;
                    case "*":
                        BsGraphicsArea.TranslateTable100Star = sb.ToString(2, cutLength).Trim();
                        break;
                    case "0":
                        BsGraphicsArea.TranslateTable1000 = sb.ToString(2, cutLength).Trim();
                        break;
                    case "1":
                        BsGraphicsArea.TranslateTable1001 = sb.ToString(2, cutLength).Trim();
                        break;
                    case "B":
                        // no idea.. only 1 char...
                        BsGraphicsArea.TranslateTable100B = sb.Length == 4 ? sb.ToString(2, 2).Trim() : sb.ToString(2, 1).Trim();
                        break;
                }
                // cut
                sb.Remove(0, sb.Length >= 4 ? 4 : sb.Length);
            }
        }

        private void UpdateFunctionKeys(string funcKeysRecvStr)
        {
            /*
                    10     FKEY-F1           PIC X(10) VALUE "F1   END  ".
                    10     FKEY-F2           PIC X(10) VALUE "F2   MEN  ".
                    10     FKEY-F3           PIC X(10) VALUE "F3   UNDO ".
                    10     FKEY-F4           PIC X(10) VALUE "F4   RET  ".
                    10     FKEY-F5           PIC X(10) VALUE "F5   BACK ".
                    10     FKEY-F6           PIC X(10) VALUE "F6   --   ".
                    10     FKEY-F7           PIC X(10) VALUE "F7   -    ".
                    10     FKEY-F8           PIC X(10) VALUE "F8   +    ".
                    10     FKEY-F9           PIC X(10) VALUE "F9   MAIL ".
                    10     FKEY-F10          PIC X(10) VALUE "F10  <    ".
                    10     FKEY-F11          PIC X(10) VALUE "F11  >    ".
                    10     FKEY-F12          PIC X(10) VALUE "F12  HELP ".
                    10     FKEY-F13          PIC X(10) VALUE "F13  MSG  ".
                    10     FKEY-F14          PIC X(10) VALUE "F14, MRK, ".
                    10     FKEY-F15          PIC X(10) VALUE "F15  DATA ".
                    10     FKEY-F16          PIC X(10) VALUE "F16  EU   ".
                    10     FKEY-F17          PIC X(10) VALUE "F17  CONV ".
                    10     FKEY-F18          PIC X(10) VALUE "F18  PALL ".
                    10     FKEY-F19          PIC X(10) VALUE "F19  PMAN ".
                    10     FKEY-F20          PIC X(10) VALUE "F20  F20  ".
                    10     FKEY-F21          PIC X(10) VALUE "F21  HC   ".
                    10     FKEY-F22          PIC X(10) VALUE "F22  F22  ".
                    10     FKEY-F23          PIC X(10) VALUE "F23  F23  ".
                    10     FKEY-F24          PIC X(10) VALUE "F24  F24  ".
            */
            int offSet = 0;

            BsFunctionKeys.TsLogout = funcKeysRecvStr[offSet++] == 'J'; // f1
            BsFunctionKeys.TsMenu = funcKeysRecvStr[offSet++] == 'J'; // f2
            BsFunctionKeys.TsCancel = funcKeysRecvStr[offSet++] == 'J'; // f3
            //no refresh anymore - BsFunctionKeys.TsRefresh = funcKeysRecvStr[offSet++] == 'J';  // f4
            offSet++;
            BsFunctionKeys.TsBack = funcKeysRecvStr[offSet++] == 'J'; // f5 
            BsFunctionKeys.TsFirstPage = funcKeysRecvStr[offSet++] == 'J'; // f6 
            BsFunctionKeys.TsPageUp = funcKeysRecvStr[offSet++] == 'J'; // f7
            BsFunctionKeys.TsPageDown = funcKeysRecvStr[offSet++] == 'J'; // f8
            BsFunctionKeys.TsMail = funcKeysRecvStr[offSet++] == 'J'; // f9
            BsFunctionKeys.TsPageLeft = funcKeysRecvStr[offSet++] == 'J'; // f10
            BsFunctionKeys.TsPageRight = funcKeysRecvStr[offSet++] == 'J'; // f11
            BsFunctionKeys.TsHelp = funcKeysRecvStr[offSet++] == 'J'; // f12
            offSet++; // f13 - ignored
            BsFunctionKeys.TsForward = funcKeysRecvStr[offSet++] == 'J'; // f14 
            offSet++; // f15 - ignored
            offSet++; // f16 - ignored
            offSet++; // f17 - ignored
            offSet++; // f18 - ignored
            offSet++; // f19 - ignored
            // ReSharper disable once RedundantAssignment
            offSet++; // f20 - ignored

            // always enabled
            //TsPrintHardcopy = funcKeysRecvStr[offSet++] == 'J';// f20
            BsFunctionKeys.TsPrintHardcopy = true;
            //offSet++;   // f22 - ignored
            //offSet++;   // f23 - ignored
            //offSet++;   // f24 - ignored
        }

        private int GetBsAttributeColorNo(string bsAttribute)
        {
            if (bsAttribute == "0000000000")
                return 0;

            string binary;
            try
            {
                binary = Convert.ToString(Convert.ToInt32(bsAttribute), 2);
            }
            catch (FormatException)
            {
                return 0;
            }
            catch (OverflowException)
            {
                return 0;
            }
            while (binary.Length < 16)
                binary = $"0{binary}";

            // now check the bytes (5,6 and 7), if they are 1, add 1
            int baseColor = 10;
            if (binary[4] == '1') // offset of 1 cause cobol starts with 1 instead of 0
                baseColor = baseColor + 4;
            if (binary[5] == '1') // offset of 1 cause cobol starts with 1 instead of 0
                baseColor = baseColor + 2;
            if (binary[6] == '1') // offset of 1 cause cobol starts with 1 instead of 0
                baseColor++;

            return baseColor;
        }
    }
}
